#include "EpollServer.h"
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
#include <signal.h>

using namespace std;


long maxLive = 120;//2分钟没操作 

EpollServer::EpollServer(int port, int write_fd)
{
    // 日志管道
    this->write_fd = write_fd;
    tcpServer = new TcpServer(port);//初始tcp
    tcpServer->TcpgetInstance(); // 初始化TCP服务器
    sharedMemory = new SharedMemory(write_fd);//初始共享内存
}

EpollServer::~EpollServer()
{
    // 发送终止消息给日志进程


    if (epoll_fd != -1) {
        close(epoll_fd);
        epoll_fd = -1;
    }

    if (tcpServer) {
        delete tcpServer;
        tcpServer = nullptr;
    }

    if (sharedMemory) {
        delete sharedMemory;
        sharedMemory = nullptr;
    }
}

//获取指定客户端的贡献时长（当前时间 - 最后活跃时间）
long EpollServer::getClientContributionTime(int client_id) {

    long current_time = static_cast<long>(time(nullptr));
    // 计算贡献时长 = 当前时间 - 最后活跃时间
    return current_time - TcpServer::client_states[client_id].alive_time;
}


void EpollServer::EpollInit()
{
    // 4. 创建epoll实例(使用更现代的epoll_create1)
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        throw runtime_error("epoll创建失败");
    }

    // 5. 添加EPOLL关注事件(添加EPOLLET边缘触发标志)
    struct epoll_event epoll_event;
    epoll_event.data.fd = this->tcpServer->getTcpServerfd();
    epoll_event.events = EPOLLIN | EPOLLET; // 添加边缘触发标志
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, this->tcpServer->getTcpServerfd(), &epoll_event) == -1) 
    {
        throw runtime_error("epoll_ctl添加服务器socket失败");
    }
    cout << "epoll (边缘触发模式) 初始化完成。。。" << endl;
}

void EpollServer::start()
{
    const int MAX_EVENTS = 64;
    struct epoll_event event_array[MAX_EVENTS];
    char body[MEMORYSIZE] = { 0 };
    HEAD head = { 0 };

    // 设置服务器socket为非阻塞(必须)
    if (!setNonBlocking(tcpServer->getTcpServerfd())) {
        throw runtime_error("设置服务器socket非阻塞失败");
    }

    // 创建共享内存读取线程
    sharedMemory->CreateThread();

    // 创建心跳检查线程
    thread heatCheck(&EpollServer::recycleClient, this);
    heatCheck.detach();

    while (true) {
        int event_num = epoll_wait(epoll_fd, event_array, MAX_EVENTS, -1);
        if (event_num < 0) {
            if (errno == EINTR) continue; // 被信号中断
            perror("epoll_wait错误");
            throw runtime_error("epoll_wait失败");
        }

        for (int i = 0; i < event_num; i++) {
            // 处理错误或挂起事件
            if (event_array[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
                int error_fd = event_array[i].data.fd;
                cerr << "连接错误或关闭 fd=" << error_fd << endl;
                closeAndCleanup(error_fd);
                continue;
            }
            // 处理新连接
            if (event_array[i].data.fd == this->tcpServer->getTcpServerfd()) {
                // 边缘触发模式下必须处理所有pending的连接
                while (true) {
                    int client_fd = accept(this->tcpServer->getTcpServerfd(), NULL, NULL);
                    if (client_fd == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                            break; // 没有更多待处理连接
                        }
                        perror("accept错误");
                        break;
                    }

                    cout << "新客户端连接 fd=" << client_fd << endl;
                    configureSocket(client_fd); //服务设为非阻塞
                    setNonBlocking(client_fd); // 客户端socket也必须非阻塞

                    // 注册到epoll(添加EPOLLET标志)
                    struct epoll_event ev;
                    ev.data.fd = client_fd;
                    ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP; // 边缘触发+对端关闭事件
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
                        perror("epoll_ctl添加客户端失败");
                        close(client_fd);
                        continue;
                    }

                    // 记录客户端心跳
                    TcpServer::client_states[client_fd].alive_time = static_cast<long>(time(nullptr));
                    cout << "记录客户端心跳 fd=" << client_fd << endl;
                    //设置为未登录状态
                    TcpServer::client_states[client_fd].isLogin = false;
                }
            }
            // 处理客户端数据(边缘触发必须完全读取所有数据)
            else if (event_array[i].events & EPOLLIN) {
                int client_fd = event_array[i].data.fd;
                auto& state = TcpServer::client_states[client_fd];
                bool connection_closed = false;

                while (true) {
                    if (state.head_bytes_read < sizeof(HEAD)) {
                        ssize_t n = read(client_fd,
                            reinterpret_cast<char*>(&state.partial_head) + state.head_bytes_read,
                            sizeof(HEAD) - state.head_bytes_read);

                        if (n <= 0) {
                            if (n == 0 || (n < 0 && (errno != EAGAIN && errno != EWOULDBLOCK))) {
                                connection_closed = true;
                            }
                            break;
                        }

                        state.head_bytes_read += n;
                        state.alive_time = static_cast<long>(time(nullptr));

                        if (state.head_bytes_read == sizeof(HEAD)) {
                            if (state.partial_head.data_len > 0) {
                                state.partial_body = new char[state.partial_head.data_len];
                                state.body_bytes_read = 0;
                            }
                            else {
                                //更新一下该客户端的存活时间
                              //添加到map容器记录当前存活时间
                               // 获取当前时间戳（秒）
                                long current_time = static_cast<long>(time(nullptr));
                                TcpServer::client_states[client_fd].alive_time = current_time;
                                //写入共享内存
                                if (!sharedMemory->Front_write(state.partial_head, nullptr, client_fd)) {
                                    cerr << "写入共享内存失败 fd=" << client_fd << endl;
                                }
                                resetClientState(state);
                                break;
                            }
                        }
                    }
                    else if (state.body_bytes_read < state.partial_head.data_len) 
                    {
                        ssize_t n = read(client_fd,
                            state.partial_body + state.body_bytes_read,
                            state.partial_head.data_len - state.body_bytes_read);

                        if (n <= 0) {
                            if (n == 0 || (n < 0 && (errno != EAGAIN && errno != EWOULDBLOCK))) {
                                connection_closed = true;
                            }
                            break;
                        }

                        state.body_bytes_read += n;
                        state.alive_time = static_cast<long>(time(nullptr));

                        if (state.body_bytes_read == state.partial_head.data_len) {
                            //更新一下该客户端的存活时间
                            //添加到map容器记录当前存活时间
                             // 获取当前时间戳（秒）
                            long current_time = static_cast<long>(time(nullptr));
                            TcpServer::client_states[client_fd].alive_time = current_time;
                            //写入共享内存
                            if (!sharedMemory->Front_write(state.partial_head, state.partial_body, client_fd)) {
                                cerr << "写入共享内存失败 fd=" << client_fd << endl;
                            }
                            resetClientState(state);
                        }
                    }

                    if (connection_closed) {
                        closeAndCleanup(client_fd);
                        break;
                    }
                }
            }
        }
    }
}

void EpollServer::resetClientState(ClientState& state) {
    if (state.partial_body != nullptr) {
        delete[] state.partial_body;
        state.partial_body = nullptr;
    }
    memset(&state.partial_head, 0, sizeof(HEAD));
    state.head_bytes_read = 0;
    state.body_bytes_read = 0;
}

void EpollServer::recycleClient()
{
    while (true)
    {    
        for (auto it = TcpServer::client_states.begin(); it != TcpServer::client_states.end(); it++)
        {
            //发送心跳包
            HEAD head = { 0 };
            head.checksum = 10;
            head.data_len = 0;
            head.index = 1;
            head.service_type = HEART; //心跳包
            write(it->first, &head, sizeof(HEAD));

            //如果当前存活时间大于心跳时间
            if (getClientContributionTime(it->first) > maxLive && it->second.isLogin==false)
            {
                cout << "心跳超时 fd" << it->first << endl;
                closeAndCleanup(it->first);//断开连接
            }
        }
        usleep(40000000); //40s检测一次
    }
}


bool EpollServer::configureSocket(int fd)
{
    // 设置非阻塞
    if (!setNonBlocking(fd)) {
        return false;
    }

    // 设置TCP_NODELAY禁用Nagle算法
    int flag = 1;
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) {
        cerr << "设置TCP_NODELAY失败: " << strerror(errno) << endl;
        return false;
    }

    // 设置SO_LINGER
    struct linger ling = { 1, 0 };  // 关闭时立即返回，丢弃未发送数据
    if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) == -1) {
        cerr << "设置SO_LINGER失败: " << strerror(errno) << endl;
        return false;
    }

    return true;
}


void EpollServer::closeAndCleanup(int fd)
{
    if (fd == -1) return;

    // 清理client_states
    auto it = TcpServer::client_states.find(fd);
    if (it != TcpServer::client_states.end()) {
        if (it->second.partial_body != nullptr) {
            delete[] it->second.partial_body;
        }
        TcpServer::client_states.erase(it);
    }
    // 从epoll中移除
    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
        cerr << "从epoll移除fd失败 " << fd << ": " << strerror(errno) << endl;
    }

    // 关闭socket（仅客户端描述符）
    if (close(fd) == -1) {
        cerr << "关闭socket失败 " << fd << ": " << strerror(errno) << endl;
    }

    // 如果是客户端描述符，从client_alive中移除
    if (TcpServer::client_states.find(fd) != TcpServer::client_states.end()) {
        TcpServer::client_states.erase(fd);
    }
    if (SharedMemory::loginNumber > 0)
    {
        SharedMemory::loginNumber--;//登录人数减一
    }

    cout << "连接关闭 fd=" << fd << endl;
}

bool EpollServer::setNonBlocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        cerr << "获取文件描述符标志失败: " << strerror(errno) << endl;
        return false;
    }

    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        cerr << "设置非阻塞模式失败: " << strerror(errno) << endl;
        return false;
    }

    return true;
}